using System;
using System.IO;
using System.Collections;
using System.Collections.Specialized;
using System.Text;
using System.Text.RegularExpressions;
using TestCoverage;
using ASOGS.Patterns;
using Reflector.Framework;
using Reflector.CodeModel;

namespace Doubler.Helpers
{
    public class MetaHelper
    {

        private static ReflectorServices _Services;

        public static ReflectorServices Services
        {
            get
            {
                return _Services;
            }
            set
            {
                _Services = value;
            }
        }

        private static void GetCallsOut(Reflector.CodeModel.IMethodDeclaration method, ref Reflector.CodeModel.IMethodDeclarationCollection methodsCalled, Hashtable methodTreeCache)
        {
            if (methodTreeCache.Contains(method))
            {
                methodsCalled.AddRange((Reflector.CodeModel.IMethodDeclarationCollection)methodTreeCache[method]);
                return;
            }
            Reflector.CodeModel.ITypeReference OwningType = (Reflector.CodeModel.ITypeReference)method.DeclaringType;

            Reflector.CodeModel.IMethodBody MethodBody = method.Body as Reflector.CodeModel.IMethodBody;
            if (MethodBody != null)
            {
                foreach (Reflector.CodeModel.IInstruction Instruction in MethodBody.Instructions)
                {
                    switch (Reflector.CodeModel.InstructionHelper.GetInstructionName(Instruction.Code))
                    {
                        case "call":
                        case "callvirt":
                        case "calli":
                        case "newobj":
                            Reflector.CodeModel.IMethodReference MethodReference = (Reflector.CodeModel.IMethodReference)Instruction.Value;
                            Reflector.CodeModel.IMethodDeclaration MethodCalled = MethodReference.Resolve();
                            Reflector.CodeModel.ITypeReference CalledOwningType = (Reflector.CodeModel.ITypeReference)MethodReference.DeclaringType;
                            if (OwningType.Resolve() == CalledOwningType.Resolve() && !methodsCalled.Contains(MethodCalled))
                            {
                                methodsCalled.Add(MethodCalled);
                                MetaHelper.GetCallsOut(MethodCalled, ref methodsCalled, methodTreeCache);
                            }
                            else if (!methodsCalled.Contains(MethodCalled))
                            {
                                methodsCalled.Add(MethodCalled);
                            }
                            break;
                    }
                }
            }
            methodTreeCache.Add(method, methodsCalled);
        }

        public static Reflector.CodeModel.IMethodDeclarationCollection GetCallsOut(Reflector.CodeModel.IMethodDeclaration method, Hashtable methodTreeCache)
        {
            if (methodTreeCache.Contains(method))
            {
                return (Reflector.CodeModel.IMethodDeclarationCollection)methodTreeCache[method];
            }
            Reflector.CodeModel.IMethodDeclarationCollection MethodCalls = new Reflector.CodeModel.Memory.MethodDeclarationCollection();
            MetaHelper.GetCallsOut(method, ref MethodCalls, methodTreeCache);
            return MethodCalls;
        }

        public static void LoadAssembliesInReflector(Reflector.CodeModel.IModule assembly, ReflectorServices reflectorServices, String pathToFindAssemblies)
        {
            foreach (Reflector.CodeModel.IAssemblyReference AssemblyRef in assembly.AssemblyReferences)
            {
                if (AssemblyRef.Resolve() == null || !reflectorServices.AssemblyManager.Assemblies.Contains(AssemblyRef.Resolve()))
                {
                    reflectorServices.AssemblyManager.Load(AssemblyRef, pathToFindAssemblies);
                    foreach (Reflector.CodeModel.IModule Module in AssemblyRef.Resolve().Modules)
                        MetaHelper.LoadAssembliesInReflector(Module, reflectorServices, pathToFindAssemblies);
                }
            }
        }

        public static bool IsNotNestedMember(Reflector.CodeModel.IMethodDeclaration member)
        {
            return IsNotNestedMember(member.Name);
        }

        public static bool IsNotNestedMember(String memberName)
        {
            return !memberName.StartsWith("get_")
                    && !memberName.StartsWith("set_")
                    && !memberName.StartsWith("add_")
                    && !memberName.StartsWith("remove_");
        }

        public static String GetFullTypeName(Reflector.CodeModel.IType type)
        {
            if (type is Reflector.CodeModel.ITypeReference)
            {
                return GetFullTypeName((Reflector.CodeModel.ITypeReference)type);
            }
            else if (type is Reflector.CodeModel.IReferenceType)
            {
                return GetFullTypeName(((Reflector.CodeModel.IReferenceType)type).ElementType);
            }
            else
            {
                return type.ToString();
            }
        }

        public static String GetFullTypeName(Reflector.CodeModel.ITypeReference type)
        {
            if (type.Resolve() != null)
            {
                return GetFullTypeName(type.Resolve());
            }
            else
            {
                if (type.Namespace == null || type.Namespace == String.Empty)
                {
                    if (type is Reflector.CodeModel.ITypeReference 
                        && ((Reflector.CodeModel.ITypeReference)type).Owner != null 
                        && ((Reflector.CodeModel.ITypeReference)type).Owner is Reflector.CodeModel.ITypeReference)
                    {
                        String Namespace = GetFullTypeName(((Reflector.CodeModel.ITypeReference)((Reflector.CodeModel.ITypeReference)type).Owner));
                        return string.Format("{0}.{1}", Namespace, type.Name);
                    }
                    else
                    {
                        return type.Name;
                    }
                }
                return String.Format("{0}.{1}", type.Namespace, type.Name);
            }
            
        }

        public static String GetFullTypeName(Reflector.CodeModel.ITypeDeclaration type)
        {
            if (type.Namespace == null || type.Namespace == String.Empty)
            {
                if (type is Reflector.CodeModel.ITypeReference
                        && ((Reflector.CodeModel.ITypeReference)type).Owner != null
                        && ((Reflector.CodeModel.ITypeReference)type).Owner is Reflector.CodeModel.ITypeReference)
                {
                    String Namespace = GetFullTypeName(((Reflector.CodeModel.ITypeReference)((Reflector.CodeModel.ITypeReference)type).Owner));
                    return string.Format("{0}.{1}", Namespace, type.Name);
                }
                else
                {
                    return type.Name;
                }
            }
            return String.Format("{0}.{1}", type.Namespace, type.Name);
        }

        public static IMethodDeclaration GetInvokeMethod(IEventReference eventRef)
        {
            ITypeReference EventType = eventRef.EventType;
            return Reflector.Helper.GetMethod(EventType.Resolve(), "Invoke").Resolve();
        }

        public static StringCollection HintDirectories = new StringCollection();

#region Helpers

        private static object TryCast(object subject, Type DesiredType)
        {
            if (subject != null)
            {
                if (subject.GetType() == DesiredType)
                {
                    return subject;
                }
                if (subject.GetType().IsSubclassOf(DesiredType))
                {
                    return subject;
                }
                if (subject.GetType().GetInterface(DesiredType.FullName) != null)
                {
                    return subject;
                }
            }
            return null;
        }
 
#endregion
 
    }
}
